package popedom

import (
	"bytes"
	"context"
	"strconv"
	"strings"

	"shqsoft.cn/pas3ui/base"
	"shqsoft.cn/pas3ui/popedom/entity"

	"gorm.io/gorm"
)

var rctx = context.Background()

// LoadUserPermsToRedis 加载用户的权限和角色到缓存
func LoadUserPermsToRedis(tx *gorm.DB, userID int) error {
	if tx == nil {
		tx = base.MYDB
	}
	key := "up:" + strconv.Itoa(userID)
	ex, err := base.RedisCli.Exists(rctx, key).Result()
	if err != nil {
		return err
	}
	if ex == 1 {
		return nil
	}
	var userPerms []entity.UserPermission
	err = tx.Where(`UserId=?`, userID).Find(&userPerms).Error
	if err != nil {
		return err
	}
	var userRoles []entity.UserRole
	err = tx.Where(`UserId=?`, userID).Find(&userRoles).Error
	if err != nil {
		return err
	}
	userPermMap := make(map[string]interface{})
	var buff bytes.Buffer
	ursLen := len(userRoles)
	for i, ur := range userRoles {
		buff.WriteString(strconv.Itoa(ur.RoleId))
		if i < ursLen-1 {
			buff.WriteString(":")
		}
	}
	userPermMap["r"] = buff.String()
	for _, up := range userPerms {
		pid := strconv.Itoa(up.PermissionId)
		userPermMap[pid] = up.PermissionType
	}
	if len(userPermMap) == 0 {
		return nil
	}
	_, err = base.RedisCli.HMSet(rctx, key, userPermMap).Result()
	if err != nil {
		return err
	}
	return nil
}

// LoadPermsToRedis 加载权限到缓存
func LoadPermsToRedis() error {
	var perms []entity.Permission
	err := base.MYDB.Order(`ParentPermissionId`).Find(&perms).Error
	if err != nil {
		return err
	}
	key := "permission"
	if _, err := base.RedisCli.Del(rctx, key).Result(); err != nil {
		return err
	}
	permMap := make(map[string]interface{})
	ppID := 0
	permLen := len(perms)
	var buff bytes.Buffer
	var perm entity.Permission
	for i := 0; i <= permLen; i++ {
		if i != permLen {
			perm = perms[i]
		}
		if i != permLen && ppID == perm.ParentPermissionId {
			buff.WriteString(strconv.Itoa(perm.ID))
			buff.WriteString(",")
		} else {
			buff.Truncate(buff.Len() - 1)
			permMap[strconv.Itoa(ppID)] = buff.String()
			if i != permLen {
				ppID = perm.ParentPermissionId
				buff.Truncate(0)
				buff.WriteString(strconv.Itoa(perm.ID))
				buff.WriteString(",")
			}
		}
	}
	if len(permMap) == 0 {
		return nil
	}
	_, err = base.RedisCli.HMSet(rctx, key, permMap).Result()
	if err != nil {
		return err
	}
	rows, err := base.MYDB.Raw(`SELECT PTID FROM t_PermissionType where ISTX=1`).Rows()
	if err != nil {
		return err
	}
	lkey := "tx_ptypes"
	txPtypes := make([]interface{}, 0, 10)
	for rows.Next() {
		var pt string
		rows.Scan(&pt)
		txPtypes = append(txPtypes, pt)
	}
	base.RedisCli.Del(rctx, lkey)
	err = base.RedisCli.RPush(rctx, lkey, txPtypes...).Err()
	return err
}

// ClearUserPermsFormRedis 清除用户的权限缓存
func ClearUserPermsFormRedis(userID int) error {
	key := "up:" + strconv.Itoa(userID)
	_, err := base.RedisCli.Del(rctx, key).Result()
	if err != nil {
		return err
	}
	return nil
}

// GetUserPermFormRedis 获取缓存里的用户权限
func GetUserPermFormRedis(userID int, permissionID int) ([]string, error) {
	key := "up:" + strconv.Itoa(userID)
	pTypesStrArr := make([]string, 0, 5)
	pTypesStr := base.RedisCli.HGet(rctx, key, strconv.Itoa(permissionID)).Val()
	if pTypesStr != "" {
		pTypesStrArr = append(pTypesStrArr, pTypesStr)
	}
	rolesStr := base.RedisCli.HGet(rctx, key, "r").Val()
	if rolesStr == "" {
		rolesStr = "16"
	}
	roles := strings.Split(rolesStr, ":")
	if !base.IsInSlice(roles, "16") {
		roles = append(roles, "16")
	}
	for _, r := range roles {
		rkey := "rp:" + r
		pTypesStr := base.RedisCli.HGet(rctx, rkey, strconv.Itoa(permissionID)).Val()
		if pTypesStr != "" {
			pTypesStrArr = append(pTypesStrArr, pTypesStr)
		}
	}
	topPt := 4
	topPids := make([]int, 0, 3)
	for _, pts := range pTypesStrArr {
		if strings.Contains(pts, "4") {
			topPt = 1
			break
		} else if strings.Contains(pts, "L") && topPt > 2 {
			topPt = 2
		} else if strings.Contains(pts, "3") && topPt > 3 {
			topPt = 3
		}
	}
	for i, pts := range pTypesStrArr {
		if topPt == 1 && strings.Contains(pts, "4") {
			topPids = append(topPids, i)
		} else if topPt == 2 && strings.Contains(pts, "L") {
			topPids = append(topPids, i)
		} else if topPt == 3 && strings.Contains(pts, "3") {
			topPids = append(topPids, i)
		} else if topPt == 4 && strings.Contains(pts, "1") {
			topPids = append(topPids, i)
		}
	}
	lkey := "tx_ptypes"
	llen := base.RedisCli.LLen(rctx, lkey).Val()
	txPtypes, err := base.RedisCli.LRange(rctx, lkey, 0, llen).Result()
	if err != nil {
		return nil, err
	}
	pTypes := make([]string, 0, 6)
	for i, pts := range pTypesStrArr {
		ptArr := strings.Split(pts, ",")
		for _, pt := range ptArr {
			if base.IsInSliceForInt(topPids, i) || !base.InStringSlice(pt, txPtypes) {
				if !base.InStringSlice(pt, pTypes) {
					pTypes = append(pTypes, pt)
				}
			}
		}
	}
	return pTypes, nil
}

// GetUserRolesFormRedis 获取缓存里用户所绑定的角色
func GetUserRolesFormRedis(userID int) ([]string, error) {
	key := "up:" + strconv.Itoa(userID)
	rolesStr, err := base.RedisCli.HGet(rctx, key, "r").Result()
	if err != nil {
		if err.Error() == "redis: nil" {
			return nil, nil
		}
		return nil, err
	}
	if rolesStr == "" {
		return nil, nil
	}
	return strings.Split(rolesStr, ":"), nil
}

// LoadRolePermsToRedis 加载角色的权限到缓存
func LoadRolePermsToRedis() error {
	var roles []entity.SysRole
	err := base.MYDB.Find(&roles).Error
	if err != nil {
		return err
	}
	for _, role := range roles {
		err = ClearRolePermsFormRedis(role.RoleId)
		if err != nil {
			return err
		}
		err = loadRolePermsToRedis(role.RoleId)
		if err != nil {
			return err
		}
	}
	return nil
}
func ReloadRolePermsToRedis(roleID int) error {
	err := ClearRolePermsFormRedis(roleID)
	if err != nil {
		return err
	}
	err = loadRolePermsToRedis(roleID)
	if err != nil {
		return err
	}
	return nil
}
func loadRolePermsToRedis(roleID int) error {
	var rolePerms []entity.RolePermission
	err := base.MYDB.Where(`RoleId=?`, roleID).Find(&rolePerms).Error
	if err != nil {
		return err
	}
	rolePermMap := make(map[string]interface{})
	for _, rolePerm := range rolePerms {
		rid := strconv.Itoa(rolePerm.PermissionId)
		rolePermMap[rid] = rolePerm.PermissionType
	}
	var userRoles []entity.UserRole
	err = base.MYDB.Where(`RoleId=?`, roleID).Find(&userRoles).Error
	if err != nil {
		return err
	}
	var buff bytes.Buffer
	ursLen := len(userRoles)
	for i, ur := range userRoles {
		buff.WriteString(strconv.Itoa(*ur.UserId))
		if i < ursLen-1 {
			buff.WriteString(":")
		}
	}
	rolePermMap["u"] = buff.String()
	key := "rp:" + strconv.Itoa(roleID)
	if len(rolePermMap) == 0 {
		return nil
	}
	_, err = base.RedisCli.HMSet(rctx, key, rolePermMap).Result()
	if err != nil {
		return err
	}
	return nil
}

// GetRoleUsersFormRedis 获取缓存里角色所绑定的用户
func GetRoleUsersFormRedis(roleID int) ([]string, error) {
	key := "rp:" + strconv.Itoa(roleID)
	usersStr, err := base.RedisCli.HGet(rctx, key, "u").Result()
	if err != nil {
		return nil, err
	}
	if usersStr == "" {
		return nil, nil
	}
	return strings.Split(usersStr, ":"), nil
}

// ClearRolePermsFormRedis 清除角色的权限缓存
func ClearRolePermsFormRedis(roleID int) error {
	key := "rp:" + strconv.Itoa(roleID)
	_, err := base.RedisCli.Del(rctx, key).Result()
	if err != nil {
		return err
	}
	return nil
}

func init() {
	err := LoadRolePermsToRedis()
	if err != nil {
		panic(err)
	}
	err = LoadPermsToRedis()
	if err != nil {
		panic(err)
	}
}
